
#include<iostream>
#include<queue>
#include<pthread.h>



template<class T , size_t maxsize = 5 > //可以给缺省参数来给出最大容量
class BlcokQueue
{
public:
    BlcokQueue()
    :_maxsize(maxsize)
    {
        //对锁和条件变量进行初始化
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_consumer_cond,nullptr);
        pthread_cond_init(&_productor_cond,nullptr);
    }

    ~BlcokQueue()
    {
        //销毁锁和条件变量
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_consumer_cond);
        pthread_cond_destroy(&_productor_cond);
    }
    //放数据
    void push(const T& data)
    {
        //第一步就要拿锁, _bq 必须要被保护起来，互斥访问
        pthread_mutex_lock(&_mutex);
        //判断是否满足生产条件
        while(_bq.size()>=_maxsize)
        {
            //不满足生产条件，首先唤醒消费者线程，然后再去等待
            pthread_cond_signal(&_consumer_cond);
            pthread_cond_wait(&_productor_cond,&_mutex);
        }
        //走到这里说明满足生产条件了
        _bq.push(data);
        //唤醒消费者
        pthread_cond_signal(&_consumer_cond);
        pthread_mutex_unlock(&_mutex);
    }

    //拿数据
    void pop(T* data) //输出型参数
    {
        pthread_mutex_lock(&_mutex);
        while(_bq.size()==0)  //判断是否满足消费条件
        {
            pthread_cond_signal(&_productor_cond);
            pthread_cond_wait(&_consumer_cond,&_mutex);
        }
        //进行消费行为
        *data=_bq.front();
        _bq.pop();
        //唤醒生产者
        pthread_cond_signal(&_productor_cond);
        pthread_mutex_unlock(&_mutex);
    }


private:
    size_t _maxsize;    
    std::queue<T> _bq;
    pthread_mutex_t _mutex;
    pthread_cond_t _consumer_cond; //消费者等待的条件变量
    pthread_cond_t _productor_cond; //生产者等待的条件变量
};

